#!/bin/bash

#-----------------------------------------------------------
# A utility for discovering which ArchLinux package contains 
# a given file. Downloads filelists for all active repos in
# pacman.conf; uses mirrors in order according to pacman's
# mirrorlist file.
#
# Peter Morris 2008
#
# Modified by tuxce.net@gmail.com
#-----------------------------------------------------------

declare -i max_retry_times=5

#db=/var/lib/pacman/filelists
db="/var/cache/pacman/pkg"
db_suffix="db.tar.gz"

for_test="n"

if [ "${for_test}" = "y" ] ; then
    db="${PWD}/var/cache/pacman/pkg"
fi

pacmanconf=/etc/pacman.conf

#-----------------------------------------------------------
# Print active repos in $pacmanconf.
#-----------------------------------------------------------
function list_repos() {
    sed -n '/REPOSITORIES/,$ s/^\[\(.*\)\]/\1/p' $pacmanconf
}

#-----------------------------------------------------------
# Download the filelist for repo $1. Assumes $mirrors
# is an array of urls to check for $file.
#-----------------------------------------------------------
function download() {
    declare -i fail_cnt=0
    repo=$1
    #file="${repo}.files.tar.gz"
    file="${repo}.${db_suffix}"
    echo "rm -f ${db}/${file}"
    rm -f ${db}/${file} 2> /dev/null
	shift
    #for mirror in $(eval echo \${$repo[*]})
    for mirror in $*
    do
      wget --connect-timeout=15 -P "$db" "$mirror/${file}"
      [ -e "${db}/${file}" ] && break
      ((fail_cnt++))
      if [ $fail_cnt -gt ${max_retry_times} ] ; then
          break
      else 
          echo "fail fail_cnt = $fail_cnt"
      fi

    done
}

#-----------------------------------------------------------
# Decompress $1 into dir $2.
#-----------------------------------------------------------
function decompress() {
    file=$1
    repo=$2

    mkdir "${db}/${repo}"
    tar -xzf "${db}/${file}" -C "${db}/${repo}"
    rm -f "${db}/${file}"
}

function print_download_url() {
    repo=$1
    file="${repo}.${db_suffix}"
	shift
    #for mirror in $(eval echo \${$repo[*]})
    for mirror in $*
    do
      echo "wget --connect-timeout=15 -P "$db" "$mirror/${file}""
      break
      #[ -e "${db}/${file}" ] && break
    done
}


function print_sync_url() {
	(LC_ALL=C pacman --debug  | grep 'adding new server' \
		| sed "s|.*adding new server URL to database '\(.*\)': \(.*\)|\1 \2|g"
		echo) | while read repo_cur url
	do
		[ -z "$repo_ex" ] && repo_ex=$repo_cur
		if [ "$repo_ex" != "$repo_cur" ] 
		then
			#echo "Fetching filelist for $repo_ex"
			print_download_url "$repo_ex" "${list[@]}"
			repo_ex=$repo_cur
			list=( )
		fi
		list=( "${list[@]}" $url )
	done
}

#-----------------------------------------------------------
# Download the filelist for each active repo in 
# pacman.conf. Try mirrors in order until successful.
#-----------------------------------------------------------
function sync() {
    echo "show repo ...."
    for repo_name in  $(list_repos) ; do
        echo "repo_name = [ ${repo_name} ]"
    done

	(LC_ALL=C pacman --debug  | grep 'adding new server' \
		| sed "s|.*adding new server URL to database '\(.*\)': \(.*\)|\1 \2|g"
		echo) | while read repo_cur url
	do
		[ -z "$repo_ex" ] && repo_ex=$repo_cur
		if [ "$repo_ex" != "$repo_cur" ] 
		then
			echo "Fetching filelist for $repo_ex"
			download "$repo_ex" "${list[@]}"
			if [[ $? == 0 ]]; then
				#echo "decompress "$file" "$repo_ex""
                echo "download ${repo_ex}.${db_suffix} successful!"
			else
				echo
				echo "Error: unable to retrieve $file from any mirror."; echo
			fi
			repo_ex=$repo_cur
			list=( )
		fi
		list=( "${list[@]}" $url )
	done
}

#-----------------------------------------------------------
# Print usage message.
#-----------------------------------------------------------
function usage() {
    echo "usage: $(basename $0) [options] [pattern]"
    echo 
    #echo "Search package filelists for [pattern]."
    echo "options:"
    echo "  $(basename $0) [-h --help]      Print this help message."
    echo "  $(basename $0) [-S --sync]      Syncronize repo db files."
    echo "  $(basename $0) [-C --clean]     Clean repo path db files."
    echo "  $(basename $0) [-P --print-url] print get db file url."
    echo "  $(basename $0) [-Q --query-db]   list and sort db file."
}

#-----------------------------------------------------------
# Start of `main'.
#-----------------------------------------------------------
case "$1" in
    -S|--sync)
        if [[ $EUID != 0 ]]; then
            echo "error: you cannot perform this operation unless you are root."
            exit 1;
        fi    

        echo "Syncronizing ${db}..."; echo

        if [ "${for_test}" = "y" ] ; then
            if [ ! -d ${db} ] ; then
                mkdir -p "$db"
            else 
                echo "rm -f ${db}/*.${db_suffix}"
                rm -f ${db}/*.${db_suffix}
            fi
        fi
        #rm -rf "$db" && mkdir -p "$db"
        echo "sync db"
        sync
    ;;

    -C|--clean)
        if [[ $EUID != 0 ]]; then
            echo "error: you cannot perform this operation unless you are root."
            exit 1;
        fi    

        echo "rm -f ${db}/*.${db_suffix}"
        rm -f ${db}/*.${db_suffix}
    ;;

    -P|--print-url)
        print_sync_url
    ;;

    -Q|--query-db)
        #echo "ls -lhSr ${db}/*.${db_suffix}"
        ls -lhSr ${db}/*.${db_suffix}
    ;;


    -h|--help)
        usage
    ;;

    *)
        if [[ $# < 1 ]]; then
            echo "not enough parameters"; echo
            usage
            exit 1
        fi

        if [[ ! -d "$db" ]]; then
            echo "File database \"$db\" does not exist!"
            echo "Have you synchronized the database?"; echo
            exit 1
        fi

        #grep -rE "$@" "$db" | sed  "s|$db/\(.*\)/files:|\1 |g"
    ;;
esac
